// -*- mode:c++ -*-
//
// 2009-2010 HIT Microelectronic Center all rights reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Date: Dec. 2009
// Authors: Gou Pengfei

output header {{
	class WROp:public TRIPSStaticInst
	{
		protected:

		/// Constructors for TRIPS G format instructions
		WROp(const char* mnem, MachInst _machInst, OpClass __opClass):
			TRIPSStaticInst(mnem, _machInst, __opClass)
		{			

			// This is explicitly statments of consumers due to the special coding format of read/write instruction
			if (V_R) {
                        if (T0_R != T1_R ) {
                            _numConsumers = 2;
                            _consumerID[0] = ( 0x1 << 8 ) | T0_R;
                            _consumerID[1] = ( 0x1 << 8 ) | T1_R;
                        } else {
                            _numConsumers = 1;
                            _consumerID[0] = ( 0x1 << 8 ) | T0_R;
                        }

                        flags[IsGRegReadValid] = true;
			} else {
			   _numConsumers = 0;
			}

			//if ( V_R ) flags[IsGRegReadValid] = true;
			if ( V_W ) {
			    flags[IsGRegWriteValid] = true;
			    _numOperands = 1;
			} else {
			    _numOperands = 0;
			}

			_predication = Disable;

		}
		
		std::string generateDisassembly(Addr pc, const SymbolTable *symTab) const;
	};

}};

output decoder {{
	std::string WROp::generateDisassembly(Addr pc, const SymbolTable* symtab) const {
		std::stringstream ss;
		ccprintf(ss, "%-10s",mnemonic);
		ss<<" ";
		ccprintf(ss, "gr[%d]", GR_R);
		printConsumer(ss,0);
		if (_numConsumers > 1) printConsumer(ss, 1);
		ss<<" ";
		ccprintf(ss, "gw[%d]", GR_W);
		return ss.str();
	}
}};

// Declarations for execute() methods.
def template WRExecDeclare {{
        Fault execute(%(CPU_exec_context)s *, Trace::EdgeInstRecord * ) const;
}};

// Basic instruction class declaration template.
def template WRDeclare {{
        /**
         * Static instruction class for "%(mnemonic)s".
         */
        class %(class_name)s : public %(base_class)s
        {
          public:
                /// Constructor.
                %(class_name)s(MachInst machInst);
                %(WRExecDeclare)s
        };
}};


// Basic instruction class execute method template.
def template WRExecute {{
        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::EdgeInstRecord *traceData) const
        {
        #if 0
                Fault fault = NoFault;
                bool write, read;

                write = xc->isExecutingWriteReg();
                read = xc->isExecutingReadReg();

                %(op_decl)s;

                bool write_true;

                assert( write  ^  read );

                if ( write ) assert( isGRegWriteValid() );
                if ( read ) assert( isGRegReadValid() );
                
                if ( write ) write_true = true;
                else if ( read ) write_true = false;
                else panic("Flags panic when execute write_read inst!\n");
                
                if (write_true ) Op0 = xc->getIntIQOperand(0);
                else Gr_r = xc->readIntRegOperand(this, 0);
                
                if(fault == NoFault)
                {
                  %(code)s;
                  if(fault == NoFault){
                  if ( !write_true )
                  {
            		uint64_t final_val = RESULT;
           		xc->setIntResult(final_val);
            		if (traceData) { traceData->setData(final_val); }
        	  } 
        	  else
        	  {
            		uint64_t final_val = Gr_w;
            		xc->setIntRegOperand(this, 0, final_val);
            		if (traceData) { traceData->setData(final_val); }
        	  }
       
                }
                }
                return fault;
                #endif
                panic("Register Read/Write class has been obsoleted.\n");
        }
}};

// There are nop insts in header, cope with it.
def template ReadWriteDecode {{
        if ( HEAD_BODY == 0 ) return new Nop(machInst);
        else return new %(class_name)s(machInst);
}};

//opt_flags+=('IQOPerands',)
def format WROp(code,*opt_flags) {{

	iop = InstObjParams(name,Name,'WROp',code,opt_flags)
	header_output = WRDeclare.subst(iop)
	decoder_output = BasicConstructor.subst(iop)
	decode_block = ReadWriteDecode.subst(iop)
	exec_output = WRExecute.subst(iop)
}};

